﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using WaitLess.Business.Data.Web.Interfaces;

namespace WaitLess.Business.Data.Web
{
    public class WebRequestor : IWebRequestor
    {
        public void Download(string requestUriString, Action<string> result, Action<Exception> fail = null)
        {
            var request = HttpWebRequest.CreateHttp(requestUriString);

            try
            {
                request.BeginGetResponse(callback => 
                {
                    try
                    {
                        var response = ReadResponse(request, callback);
                        result(response);
                    }
                    catch (Exception ex)
                    {
                        HandleErrors(ex, fail);
                    }
                }, 
                state: null);
            }
            catch (Exception ex)
            {
                HandleErrors(ex, fail);
            }
        }

        public void Post(string requestUriString, Dictionary<string, string> parameters, Action<string> result, Action<Exception> fail = null)
        {
            var request = HttpWebRequest.CreateHttp(requestUriString);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            request.BeginGetRequestStream(callback =>
            {
                WritePostBody(parameters, request, callback);
                PostRequest(result, request, fail);

            }, state: null);
        }

        private void WritePostBody(Dictionary<string, string> parameters, HttpWebRequest request, IAsyncResult callback)
        {
            using (var requestStream = request.EndGetRequestStream(callback))
            {
                using (var sw = new StreamWriter(requestStream))
                {
                    foreach (var parameter in parameters)
                    {
                        sw.Write(string.Format("{0}={1}&", parameter.Key, parameter.Value));
                    }
                }
            }
        }

        private void PostRequest(Action<string> result, HttpWebRequest request, Action<Exception> fail = null)
        {
            request.BeginGetResponse(a =>
            {
                try
                {
                    using (var response = request.EndGetResponse(a))
                    {
                        using (var stream = response.GetResponseStream())
                        {
                            using (var reader = new StreamReader(stream))
                            {
                                result(reader.ReadToEnd());
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    HandleErrors(ex, fail);
                }
            }, state: null);
        }

        private string ReadResponse(HttpWebRequest request, IAsyncResult result)
        {
            using (var response = request.EndGetResponse(result))
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        private void HandleErrors(Exception ex, Action<Exception> fail = null)
        {
            var webException = ex as WebException;

            if (webException != null && webException.Status == WebExceptionStatus.RequestCanceled)
                return;

            if (fail != null)
                fail(ex);
            else
                throw ex;
        }
    }
}